/********************************************************************************
 * Copyright (c)2016-2020, ShenZhen WanJiaAn Technology CO.,LTD.
 * All Rights Reserved.
 *
 * File Name     : mcu_update_dev.c
 * Author        : joki.zhu
 * Date          : 2019-11-18
 *
 * Record        :
 * 1.Date        : 2019-11-18
 *   Author      : joki.zhu
 *   Modification: Created file
 ********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <linux/completion.h>
#include "shell.h"
#include "sys/time.h"
#include "sys/prctl.h"
#include "asm/io.h"
#include "los_mux.h"
#include "los_task.h"
#include "los_sem.h"
#include "hisoc/uart.h"
#include "uart.h"
#include "pm/hi_type.h"
#include <pthread.h>
#include "mcu_update_dev.h"
#include "UartDevConf.h"
#include "../kfifo.h"

#define  RD_MSGBUF_LEN    128

static AV_BOOL                      s_bUartHostInit  = AV_FALSE;
UartDevRecvCallback                 s_cbkUartHostRcv = AV_NULL;
static pthread_t                    g_tUartHostDetect;
static pthread_mutex_t              s_tUartHostMutex;
static AV_U8                        g_USART_Receive_Buf[UART2_BUF_LEN];
static struct kfifo                 g_UartRecvFifo;
static AV_U8                        g_frameBuf[UF1_MAX_LEN];
//static AV_INT                       g_s32gUart2Fd = -1;
extern  int g_s32gUart2Fd;

static long g_timStamp[4];
static long getTimeUsec(AV_VOID)
{
    struct timeval t;
    gettimeofday(&t, 0);
    return (long)((long)t.tv_sec * 1000 * 1000 + t.tv_usec);
}

static void PrintTimeStamp(void)
{
    int i = 0;
    for (i = 0; i < (int)(sizeof(g_timStamp) / sizeof(g_timStamp[0])); i++)
    {
        MLOGD("time stamp %d: %ld: \n", i, g_timStamp[i]);
    }

    return;
}

static int HAL_UART_RecvData(AV_INT fd, AV_U8* pBuf, AV_U32 bufLen)
{
    AV_INT retReadLen = 0;
    AV_U16  len = 0;
    AV_U8   len_1 = 0;
    AV_U8   len_h = 0;
    AV_U16  rec_len = __kfifo_len(&g_UartRecvFifo);
    AV_U16  head = 0;
    AV_U8   head_l = 0;
    AV_U8   head_h = 0;

    if (rec_len >= UF1_MIN_LEN)
    {
        head_l = g_UartRecvFifo.buffer[(g_UartRecvFifo.out + UF_HEAD_OFFSET) & (g_UartRecvFifo.size - 1)];
        head_h = g_UartRecvFifo.buffer[(g_UartRecvFifo.out + UF_HEAD_OFFSET + 1) & (g_UartRecvFifo.size - 1)];
        head = (head_h << 8 | head_l) & 0xffff;
        
        if (UARTMSG_MSGDATA_HEAD == head)
        {
            len_1 = g_UartRecvFifo.buffer[(g_UartRecvFifo.out + UF_LEN_OFFSET) & (g_UartRecvFifo.size - 1)];
            len_h = g_UartRecvFifo.buffer[(g_UartRecvFifo.out + UF_LEN_OFFSET + 1) & (g_UartRecvFifo.size - 1)];
            len = (len_h << 8 | len_1) & 0xffff;
            
            if (len == 0)
            {
                __kfifo_get(&g_UartRecvFifo, pBuf, 1);                           //当前的命令长度为0，丢弃
                MLOGD("discard byte: 0X%02X \n" , pBuf[0]);
            }
            else if ((rec_len >= len) && (bufLen >= len))
            {
                retReadLen = __kfifo_get(&g_UartRecvFifo, pBuf, len);
            }
        }
        else
        {
            __kfifo_get(&g_UartRecvFifo, pBuf, 1);                              //如果当前位置不是命令起始标志，则丢弃
            MLOGD("discard byte: 0X%02X \n" , pBuf[0]);
        }
    }
    else
    {
        __kfifo_get(&g_UartRecvFifo, pBuf, 1);
        MLOGD("discard111 byte: 0X%02X \n" , pBuf[0]);
    }

    return retReadLen;
}

static void *UARTOST_Thread(void *args)
{
    int             ret;
    unsigned char   rbuf[RD_MSGBUF_LEN];
    int             putLen;
    int             readLen = 0;
    fd_set          fsRead;
    int             fsSel;
    struct  timeval time;

    prctl(PR_SET_NAME, (unsigned long)"UARTOST_Thread", 0, 0, 0);
    pthread_detach(pthread_self());

    printf("g_s32gUart2Fd ============= %d\n", g_s32gUart2Fd);
    while (1)
    {
        FD_ZERO(&fsRead);
        FD_SET(g_s32gUart2Fd, &fsRead);
        time.tv_sec = 10;
        time.tv_usec = 0;
        fsSel = select(g_s32gUart2Fd + 1, &fsRead, NULL, NULL, &time);

        if (fsSel)
        {
            ret = read(g_s32gUart2Fd, rbuf, RD_MSGBUF_LEN);
            g_timStamp[2] = getTimeUsec();

            printf("ret ============== %d\n", ret);
            if (ret < -1)
            {
                MLOGD("uartMSG read error ret= %d \n", ret);
                continue;
            }
            else
            {
                
                putLen = __kfifo_put(&g_UartRecvFifo, rbuf, ret);                
                if (putLen == 0)
                {
                    MLOGD("kfifo full... \n");
                }
            }

            do
            {
                readLen = HAL_UART_RecvData(g_s32gUart2Fd,  g_frameBuf, sizeof(g_frameBuf));                
                if ( (readLen >= UF1_MIN_LEN)  && (AV_NULL != s_cbkUartHostRcv))
                {
                    g_timStamp[3] = getTimeUsec();
                    s_cbkUartHostRcv(g_frameBuf, readLen);
                }
            }
            while (readLen > UF1_MIN_LEN);
        }
        else if (fsSel < 0)
        {
            MLOGE("select failed!\n");
            continue;
        }
        else if (fsSel == 0 )
        {
            MLOGD("get uart char reselect \n");
            continue;
        }
    }

    return NULL;
}

int UartDevInit(UartDevRecvCallback pRecvCallback)
{
    int s32Ret;

    UARTMSGCHECK_EXPR(s_bUartHostInit == AV_FALSE, AV_FAILURE);
    UARTMSGCHECK_POINTER(pRecvCallback, AV_FAILURE);

#if 0
    //3518EV300
    writew(0x1002, 0x112C0070);    //UART1_RXD
    writew(0x1052, 0x112C0074);    //UART1_TXD

    g_s32gUart2Fd = open("/dev/uartdev-1", O_RDWR | O_NOCTTY | O_NDELAY);

    if (g_s32gUart2Fd < 0)
    {
        g_s32gUart2Fd = -1;
        MLOGE("uartmsg : open %s with %d s32Ret = %d\n", "/dev/uartdev-X", O_RDWR, g_s32gUart2Fd);
        return AV_FAILURE;
    }

    s32Ret = ioctl(g_s32gUart2Fd, UART_CFG_BAUDRATE , UART_BAUDRATE);
    if (0 != s32Ret)
    {
        MLOGE("uartmsg : error !! set uart baudrate error, s32Ret = %d !!\n\n", s32Ret);
    }
#endif

	memset(g_USART_Receive_Buf, 0, sizeof(g_USART_Receive_Buf));
    __kfifo_init(&g_UartRecvFifo, g_USART_Receive_Buf, sizeof(g_USART_Receive_Buf));
    s_bUartHostInit = AV_TRUE;
    pthread_mutex_init(&s_tUartHostMutex, NULL);
    s32Ret = pthread_create(&g_tUartHostDetect, 0, UARTOST_Thread, NULL);
    if (s32Ret != 0 )
    {
        MLOGE("uartmsg : mcu host create thread fail.\n");
        close(g_s32gUart2Fd);
        g_s32gUart2Fd = -1;
        s_bUartHostInit = AV_FALSE;
        return s32Ret;
    }

    s_cbkUartHostRcv = pRecvCallback;
    MLOGD("uart host init ok \n");
    
    return AV_SUCCESS;
}

int UartDevSendBuf(AV_U8 *pBuf, AV_U32 bufLen)
{
    AV_INT ret = AV_SUCCESS;

    UARTMSGCHECK_EXPR(s_bUartHostInit == AV_TRUE, AV_FAILURE);
    UARTMSGCHECK_POINTER(pBuf, AV_FAILURE);
    UARTMSGCHECK_EXPR(bufLen > 0, AV_FAILURE);

    pthread_mutex_lock(&s_tUartHostMutex);
    g_timStamp[0] = getTimeUsec();

    ret = write(g_s32gUart2Fd, pBuf, bufLen);
    //MLOGD("pBuf[0]:0x%x pBuf[1]:0x%x pBuf[2]:0x%x pBuf[3]:0x%x pBuf[4]:0x%x\n", pBuf[0], pBuf[1], pBuf[2], pBuf[3], pBuf[4]);
    g_timStamp[1] = getTimeUsec();
    pthread_mutex_unlock(&s_tUartHostMutex);

    if (ret != (AV_INT)bufLen)
    {
        MLOGE("uartmsg : HI_HAL_UARTMSG_SendBuf : send (fd=%d) error(%d) !!\n", g_s32gUart2Fd, ret);
        ret = AV_FAILURE;
    }
    else
    {
        ret = AV_SUCCESS;
    }

    return AV_SUCCESS;    
}

int UartDevDeinit(void)
{
    AV_INT ret;

    if (s_bUartHostInit == AV_TRUE)
    {
        pthread_mutex_lock(&s_tUartHostMutex);
        s_bUartHostInit = AV_FALSE;
        ret = pthread_join(g_tUartHostDetect, NULL);

        if (ret != 0)
        {
            //MLOGE("uartmsg : g_tUartHostDetect: pthread_join failed\n");
            pthread_mutex_unlock(&s_tUartHostMutex);
            return ret;
        }

        s_cbkUartHostRcv = AV_NULL;
        close(g_s32gUart2Fd);
        g_s32gUart2Fd = -1;

        pthread_mutex_unlock(&s_tUartHostMutex);
        pthread_mutex_destroy(&s_tUartHostMutex);
        memset(&s_tUartHostMutex, 0, sizeof(s_tUartHostMutex));
    }

    PrintTimeStamp();

    return AV_SUCCESS;    
}

